/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

// ============================================================================================================================
#include <dylab/simobject/masspoints/MassPointsFeatureBase.h>

// ============================================================================================================================
dylab::MassPointsFeatureBase::MassPointsFeatureBase(ComModelStructure * _parentModel)
: ComModelStructure::FeatureBase<IMassPointsFeature>(_parentModel)
{ 
}
//-----------------------------------------------------------------------------
void dylab::MassPointsFeatureBase::reserveHistoryStates(uint32_t _noStates)
{
    // for each structure massPoint reserve the requested number of its history states
    for (MassPointContainer::Iterator mp(massPointIterator()); mp.isValid(); mp++)
    {   
		mp->reserveHistoryStates(_noStates);
	}
}
//-----------------------------------------------------------------------------
void dylab::MassPointsFeatureBase::applyPointMagnetForce(const Vector3 & _magnet, 
														   real_t _radius, real_t _forceCoeff, 
														   real_t _attenuationExp)
{
    // for all mass points
    for (MassPointContainer::Iterator mp(massPointIterator()); mp.isValid(); mp++)
    {
        // compute the force direction
        Vector3 forceDir = _magnet - mp->currState().position;

		// compute the length to the mass point
        real_t dist = forceDir.length();        

		// if the length is not near zero and is lower than the specified radius
		if (!Math::almostZero(dist) && (dist <= _radius)) 
        {         
			// compute force magnitude
            real_t forceMag = _forceCoeff * (1 - pow(dist, _attenuationExp) / pow(_radius, _attenuationExp));

			// normalise the force vector
            forceDir.normalise();

			// add the normalized force direction multiplied by the force magnitude
			mp->currState().force += forceDir * forceMag;
        }
    }
}
//-----------------------------------------------------------------------------
void dylab::MassPointsFeatureBase::applyPointMagnetForce(MassPoint::id_t _massPointId, real_t _radius, 
														   real_t _forceCoeff, real_t _attenuationExp)
{    
	// retrieve the mass point's position and delegate the call
    applyPointMagnetForce(massPointReader().get(_massPointId)->currState().position, _radius, _forceCoeff, _attenuationExp);
}
//-----------------------------------------------------------------------------